#include "EpilTableConstructorInterpreter.h"
#include "EpilInterpreter.h"
#include "EpilInterpreterException.h"
#include "EpilFieldIndexInitializerCode.h"
#include "EpilFieldItemInitializerCode.h"
#include "EpilFieldKeyInitializerCode.h"
#include "EpilExpressionInterpreter.h"


EpilTableConstructorInterpreter::EpilTableConstructorInterpreter( EpilInterpreter * interpreter )
: EpilInterpreterBase( interpreter )
{
}


void EpilTableConstructorInterpreter::Run( const EpilTableConstructorExpressionCode * code )
{
	m_table = this->GetInterpreter()->CreateTableObject();

	int curItemIndex = 1;

	const EpilFieldInitializerCodeList & initializerCodes = code->GetInitializers();

	for( EpilFieldInitializerCodeList::const_iterator it = initializerCodes.begin(); it != initializerCodes.end(); ++it )
	{
		const EpilFieldInitializerCodeBase * initializerCode = *it;

		EpilExpressionInterpreter ei( this->GetInterpreter() );
		try
		{
			ei.Run( initializerCode->GetExpression() );
		}
		catch( ... )
		{
			m_table->ReleaseCopy();
			throw;
		}
		EpilObject * value = ei.GetObject();

		switch( initializerCode->GetType() )
		{
		case ECT_FieldIndexInitializer:
			{
				const EpilFieldIndexInitializerCode * indexInitializerCode = static_cast<const EpilFieldIndexInitializerCode *>( initializerCode );
				const EpilExpressionCodeBase * indexExpr = indexInitializerCode->GetIndexExpression();
				
				EpilExpressionInterpreter indexInterpreter( this->GetInterpreter() );
				indexInterpreter.Run( indexInitializerCode->GetIndexExpression() );
				EpilObject * key = indexInterpreter.GetObject();

				m_table->SetField( key, value );
			}
			break;
		case ECT_FieldItemInitializer:
			{
				m_table->SetField( curItemIndex, value );
				curItemIndex++;
			}
			break;
		case ECT_FieldKeyInitializer:
			{
				const EpilFieldKeyInitializerCode * keyInitializerCode = static_cast<const EpilFieldKeyInitializerCode *>( initializerCode );
				tstring key = keyInitializerCode->GetKey();
				m_table->SetField( key, value );
			}
			break;
		}
	}
}